/*
    <one line to give the library's name and an idea of what it does.>
    Copyright (C) 2013  Guillaume <email>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

/*!
 * \file msSamplerExplicit.h
 * \brief An explicit sampler
 * \author G.Reinisch
 * \date 2013
 */
#ifndef MSSAMPLEREXPLICIT_H
#define MSSAMPLEREXPLICIT_H

#include <msSampler.h>
#include <cstdlib>
#include <ctime>

namespace atomism
{

/** \class msSamplerExplicit
* \brief Samples a predefined chain of coordinates values
*
*
*/  
class msSamplerExplicit : public msSampler
{ 

protected:	
   
      static msRegistrar Registrar;
      static bool  isSamplerExplicitRegisteredInPython;
      static msRegister* createInstance() { return new msSamplerExplicit; }
      void registryInPython();
      
      msSamplerExplicit() : msSampler() { constructVar("msSamplerExplicit","SamplerExplicit","linear sampler"); }  
      
public:
  
     void update()  { msSampler::update();
                      };
		     
     void initialize() {  msSampler::initialize();
			  declareAttribute< vector< vector<double> > >(Samples,"Samples");
			  };
			    
     static boost::shared_ptr<msSamplerExplicit> New(){
             
               boost::shared_ptr<msSamplerExplicit> T( new msSamplerExplicit );
	       T->initialize(); T->update();
	       return T;
	       }
     
     virtual boost::shared_ptr<msTreeMapper> clone() { 
            boost::shared_ptr<msSamplerExplicit> clone = New(); 
	    clone->msTreeMapper::operator=(*this);					      
	    return clone;
            }    
     
     bool getNextPoint(boost::shared_ptr<msGeneralizedCoordinates> coor){
       
         if( nScanned==Samples.size()-1 ){ nScanned=0; return 0;}
             
         if(coor->noOfDim() != Samples[nScanned].size() )
	      BOOST_THROW_EXCEPTION(msError("coordinates (size="+output::getString<int>(coor->noOfDim())+") and data points loaded "+
	                                    "(size="+output::getString<int>( Samples[nScanned].size())+") are not coherent ("+
					     "nscanned="+output::getString<int>( nScanned )+")",
				            "bool getNextPoint(boost::shared_ptr<msGeneralizedCoordinates> coor)",
					     getFullId())
				    );
	 coor->setCoordinates(Samples[nScanned]);
	 nScanned++;
	 return 1;
      };

     boost::shared_ptr<msTreeMapper> getRndPoint(boost::shared_ptr<msGeneralizedCoordinates> coor){
          
	 nScanned = Samples.size() * std::rand() / double(RAND_MAX);
	 coor->setCoordinates(Samples[nScanned]);
         return mySharedPtr();
     };

     boost::shared_ptr<msTreeMapper> setSample(boost::shared_ptr<msGeneralizedCoordinates> coor,size_t i){
     
         if(i>=Samples.size())
            BOOST_THROW_EXCEPTION(msError("indice out of range",
		   		     "boost::shared_ptr<msTreeMapper> setSample(boost::shared_ptr<msGeneralizedCoordinates> coor,size_t i)",
				      getFullId())
				    );
         coor->setCoordinates(Samples[i]);
         return mySharedPtr();
     }
     
     std::ostream& print(std::ostream&) const;
     
     boost::shared_ptr<msTreeMapper> addSample(const vector<double>& sample) {
       
		     if( (Samples.size()>0) && (Samples[Samples.size()-1].size()!=sample.size())) 		       
		         BOOST_THROW_EXCEPTION(msError("sample size not consistent with previous sample",
				               "boost::shared_ptr<msTreeMapper> msSamplerExplicit::addSample(const vector<double>& sample)",
					        getFullId())
				    );		      
		     Samples.push_back(sample);
		     return mySharedPtr();
		     }
     boost::shared_ptr<msTreeMapper> clear(){ Samples.clear();return mySharedPtr();} 
private:
  
     vector< vector<double> >  Samples;
};

}
#endif // MSDIRACS_H
